﻿using System.IO;
using System.Text.Json.Serialization.Metadata;
using DimensionsHelper.Common.Contracts;
using DimensionsHelper.Common.Contracts.Services;
using DimensionsHelper.Common.Utils;

namespace DimensionsHelper.Client.ViewModels;

public abstract partial class JsonLoaderViewModel<T>(IServiceProvider serviceProvider)
    : JsonLoaderViewModelBase(serviceProvider), IProjectOption<T>
    where T : class, new()
{
    protected abstract JsonTypeInfo<T> LoadingTypeInfo { get; }

    public abstract void LoadOption(T source);

    public abstract bool TryWriteOption(T target);


    public override bool LoadJson()
    {
        if (string.IsNullOrEmpty(JsonPath) || !File.Exists(JsonPath))
        {
            return false;
        }

        try
        {
            string jsonText = OptionalFileSource.ReadJson(JsonPath);
            T? obj = JsonHelper.ReadJson(jsonText.AsSpan(), LoadingTypeInfo);

            if (obj == null)
            {
                ReportService?.Error(ProjectErrorMessages.JsonFileLoadFailed, JsonPath);
                return false;
            }

            LoadOption(obj);
            return true;
        }
        catch (Exception e)
        {
            ReportService?.Error(ProjectErrorMessages.JsonFileDeserializeFailed, JsonPath, e.Message);
            return false;
        }
    }


    public async override Task<bool> SaveJson(bool saveAs)
    {
        if (saveAs || string.IsNullOrEmpty(JsonPath) || OptionalFileSource.IsPresetJson(JsonPath))
        {
            if (await App.GetService<IFilePikerService>()!.SaveFileAsync(FileFilters.Json) is not { Length: > 0 } jsonPath)
            {
                return false;
            }

            JsonPath = jsonPath;
        }

        T optionObj = new();
        if (!TryWriteOption(optionObj))
        {
            ReportService?.Error(ProjectErrorMessages.JsonSerializeFailed, JsonPath);
            return false;
        }

        JsonHelper.WriteJson(optionObj, LoadingTypeInfo, JsonPath);
        ReportService?.Log(ProjectInformation.JsonExportFinished, JsonPath);
        return true;
    }


    [RelayCommand]
    private async Task SelectJsonFile()
    {
        if (await App.GetService<IFilePikerService>()!.PickSingleFileAsync(FileFilters.Json) is not { Length: > 0 } jsonPath ||
            string.Equals(jsonPath, JsonPath, StringComparison.OrdinalIgnoreCase))
        {
            return;
        }

        JsonPath = jsonPath;
        LoadJson();
    }
}